package com.ququ.syb.entrance.aop;

import com.alibaba.fastjson.JSON;
import com.ququ.common.result.ResultJson;
import com.ququ.common.utils.MapUtil;
import com.ququ.syb.common.constant.EncryptTypeConstant;
import com.ququ.syb.entrance.fegin.ApplicationFegin;
import com.ququ.syb.entrance.mongo.PostLogDao;
import com.ququ.syb.entrance.po.RequestResponseLog;
import com.ququ.syb.entrance.service.SecurityService;
import com.ququ.syb.entrance.vo.SybResult;
import com.ququ.syb.entrance.vo.SybResultData;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Macro on 2017/3/9.
 */
@Aspect
@Configuration
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(LogAspect.class);

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    @Autowired
    private PostLogDao postLogDao;
    @Autowired
    private SecurityService securityService;
    @Autowired
    private ApplicationFegin applicationFegin;

    //定义切点Pointcut
    @Pointcut("execution(* com.ququ.syb.entrance.controller.*.*(..))")
    public void excudeService(){

    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String uri = request.getRequestURI();
        Map<String,Object> parameterMap = new HashMap<>();
        Map<String,Object> dataMap = null;
        for (String paramkey: request.getParameterMap().keySet()){
            parameterMap.put(paramkey,request.getParameter(paramkey));
        }
        Map<String,String> headerMap = new HashMap<>();
        Enumeration<String> headernames = request.getHeaderNames();
        while (headernames.hasMoreElements()){
            String headername = headernames.nextElement();
            headerMap.put(headername,request.getHeader(headername));
        }
        logger.debug("接口请求header={}",headerMap);
        logger.debug("接口请求开始, 请求地址uri: {}, 请求参数: {}", uri, JSON.toJSONString(parameterMap));
        //记录到MongoDb日志
        if (uri.equals("/"))
            return pjp.proceed();
        String accountid = parameterMap.get("accountid").toString();
        String appcode = headerMap.get("appcode");
        String tradenum = null;
        if (accountid == null || appcode == null)
            return new SybResult(-1, "接口参数错误", "",accountid==null?"":accountid);
        Integer encryptType = Integer.valueOf(parameterMap.get("encryptiontype").toString());
        if (encryptType == EncryptTypeConstant.AES) {
            String data = securityService.decrypt(parameterMap.get("data").toString(),accountid);
            dataMap = JSON.parseObject(data,Map.class);
            parameterMap.put("data",dataMap);
        }
        RequestResponseLog requestResponseLog = new RequestResponseLog();
        Date begin = new Date();
        requestResponseLog.setTime(simpleDateFormat.format(begin));
        requestResponseLog.setController(uri);
        requestResponseLog.setRequestparam(parameterMap);
        requestResponseLog.setAccountid(accountid);
        requestResponseLog.setAppcode(appcode);
        requestResponseLog.setRequestheader(headerMap);
        requestResponseLog = postLogDao.save(requestResponseLog);
        // result的值就是被拦截方法的返回值
        String controller = uri.replace("/syb/controller/","");
        if (controller.equals("p0211"))
            tradenum = dataMap.get("tradenum").toString();
        ResultJson checkResult = null;
        if (uri.equals("/") || uri.equals("/error"))
            checkResult = new ResultJson();
        else
            checkResult = applicationFegin.checkApplicationControllerAccessPermission(controller.replace("/",""),appcode);
        if (checkResult.getStatus() == 1) {
            Object result = pjp.proceed();
            Date end = new Date();
            requestResponseLog.setResponsetime(simpleDateFormat.format(end));
            requestResponseLog.setTtl((int) (end.getTime()-begin.getTime()));
            if (result instanceof String) {
                SybResult sybResult = JSON.parseObject(result.toString(), SybResult.class);
                if (uri.equals("/error")){
                    requestResponseLog.setController(sybResult.getSign());
                    sybResult.setSign("");
                    result = JSON.toJSONString(sybResult);
                }
                requestResponseLog.setResponseparam(sybResult);
            }else {
                requestResponseLog.setResponseparam((SybResult) result);
                SybResultData sybResultData= (SybResultData) ((SybResult) result).getData();
                if (controller.equals("p0210") || controller.equals("p1001")) {
                    Map<String,Object> map = MapUtil.beanToMap(sybResultData.getResult());
                    tradenum = map.get("tradenum").toString();
                }
            }
            if (controller.equals("p0210") || controller.equals("p0211") || controller.equals("p1001"))
                requestResponseLog.setTradenum(tradenum);
            postLogDao.save(requestResponseLog);
            logger.debug("接口请求结束，controller的返回明文值是{}", result instanceof String?result : JSON.toJSONString(result));
            //加密result
            if (result instanceof SybResult) {
                SybResult sybResult = (SybResult) result;
                if (sybResult.getData() instanceof SybResultData) {
                    SybResultData sybResultData = (SybResultData) sybResult.getData();
                    if (encryptType == EncryptTypeConstant.AES)
                        sybResultData.setResult(securityService.encrypt(JSON.toJSONString(sybResultData.getResult()), accountid, encryptType));
                    sybResult.setData(sybResultData);
                }
                logger.debug("接口请求结束，controller的返回密文值是{}", JSON.toJSONString(sybResult));
                return sybResult;
            }else
                return result;
        }else {
            return JSON.toJSONString(new SybResult(-1, "应用无权访问本接口", securityService.sign(new SybResultData(accountid,""), appcode),accountid));
        }
    }
}
